<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head profile="http://gmpg.org/xfn/11">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>魔方FE &raquo; Category &raquo; 性能优化</title> 
<link rel="pingback" href="http://cubefe.com/xmlrpc.php" />
<link rel="alternate" type="application/rss+xml" title="魔方FE &raquo; Feed" href="http://cubefe.com/feed/" />
<link rel="alternate" type="application/rss+xml" title="魔方FE &raquo; 评论Feed" href="http://cubefe.com/comments/feed/" />
<link rel="alternate" type="application/rss+xml" title="魔方FE &raquo; 性能优化分类目录Feed" href="http://cubefe.com/category/wpo/feed/" />
<link rel='stylesheet' id='css-css'  href='http://cubefe.com/wp-content/themes/glossy-stylo/style.css?ver=3.7.5' type='text/css' media='all' />
<script type='text/javascript' src='http://cubefe.com/wp-content/plugins/custom-post-view-generator//libs/flowplayer/flowplayer-3.2.6.min.js'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/jquery.js?ver=1.10.2'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1'></script>
<script type='text/javascript' src='http://cubefe.com/wp-content/plugins/custom-post-view-generator/libs/smartpaginator/smartpaginator.min.js'></script>
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://cubefe.com/xmlrpc.php?rsd" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://cubefe.com/wp-includes/wlwmanifest.xml" /> 
<meta name="generator" content="WordPress 3.7.5" />
	<style type="text/css">.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style>
<style type="text/css" id="custom-background-css">
body.custom-background { background-color: #000000; background-image: url('http://cubefe.com/wp-content/themes/glossy-stylo/images/bg.jpg'); background-repeat: repeat; background-position: top left; background-attachment: fixed; }
</style>
<meta id="syntaxhighlighteranchor" name="syntaxhighlighter-version" content="3.1.3" />
<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "//hm.baidu.com/hm.js?eabc7e45403336d4d9b13ae230c63f0e";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body class="archive category category-wpo category-5 custom-background">
<div id="page">
<div id="header" role="banner">
	<div id="headerimg">
		<h1><a href="http://cubefe.com">魔方FE</a></h1>
		<div class="description">魔方FE前端开发团队</div>
	</div>
</div>
	<div id="content" class="narrowcolumn" role="main">
	
	<div id="postbg">

<div id="postheader"></div>
				<div class="post">

		 	   	  		<h2 class="pagetitle">Archive for the &#8216;性能优化&#8217; Category</h2>
 	  </div>
<div id="postfooter"></div>

		<div style="display:none;" class="navigation">
			<div class="alignleft"></div>
			<div class="alignright"></div>
		</div>

				<div id="test">
<div id="postheader"></div>
				<div class="post">
				<h3 id="post-360"><a href="http://cubefe.com/img_base64/" rel="bookmark" title="Permanent Link to 一种基于Base64的图片动态合并下载技术">一种基于Base64的图片动态合并下载技术</a></h3>
				<small>2014/08/19</small>

				<div class="entry">
					<p>请无视这个听起来很专利的Title，其实原理很简单，就像大家都知道的CSS Sprite一样，本质都是通过<strong>将一堆小图合并下载</strong>，达到<strong>减少HTTP请求、加快页面展现</strong>的效果。</p>
<p>与CSS Sprite不同的是，本技术可以做到图片的在线动态合并，这样就为动态出图提供了加速下载的可能。</p>
<p>应用场景和实际效果：某厂搜索结果右侧小图，你懂的。实际加速效果百毫秒以上。</p>
<p>废话不多说，先看流程图：</p>
<p><img class="alignnone size-full wp-image-364" alt="Base64流程图" src="http://cubefe.com/wp-content/uploads/2014/08/Base64流程图1.jpg" width="689" height="448" /></p>
<p>这里有两个关键的优化点：1）小图请求大部分耗时其实是在DNS解析和连接的建立上，下载本身非常快，因此合并后可以显著减少这部分耗时。2）请求发起的时机被提前了，放到了页面一开始，这个很重要，因为请求合并后体积会变大，下载时间会稍微变长，因此越早发起收益越大。当然，一定要发异步请求哦。</p>
<p>下面是流程解读：</p>
<p>1. 后端策略：</p>
<p>取到本次页面展现需要进行合并的小图url，根据url生成唯一id。（主要是为了后面减小请求长度，并用于标识图片）</p>
<p>2. 模板插件：</p>
<p>将原来的图片输出方式：</p>
<pre class="brush: php; title: ; notranslate" title="">
&lt;img src=&quot;{$src}&quot;&gt;
</pre>
<p>改为调用插件输出：</p>
<pre class="brush: php; title: ; notranslate" title="">
&lt;img {$src|img_base64_pluggin}&gt;
</pre>
<p>当然，插件需要自己写了。主要功能就是：<br />
1. 判断传入的src是否在第一步后端处理过程生成的src列表中？<br />
如果不存在，则输出原始src；如果存在，则输出</p>
<pre class="brush: php; title: ; notranslate" title="">
data-src=$src data-base64-id=$id
</pre>
<p>3. JS组件</p>
<p>Base64前端核心代码，位置一定要放到页面的开始，尽早把请求发出来，请求参数就是后端传来的id列表。另外要接收返回内容做回填图片的处理。回填时，跟据图片id找到页面DOM中的data-base64-id属性所在的&lt;img&gt;，直接设置base64内容为&lt;img&gt;的src即可。需要注意的是，有些浏览器不支持Base64渲染，如IE6,7。那么兼容方式是提前判断UA、走普通输出，或者监听&lt;img&gt;的onload事件，如果没触发，说明不支持base64，那就把之前预存在data-src属性的原始url，设置到src属性即可。</p>
<p>具体代码涉及隐私，就不贴了，sorry，其实按上面说的来写，逻辑不复杂。</p>
<p>4. Base64服务端</p>
<p><img class="alignnone size-full wp-image-363" alt="Base64服务端处理过程" src="http://cubefe.com/wp-content/uploads/2014/08/Base64服务端处理过程.jpg" width="654" height="306" /></p>
<p>好了，总结一下，基于Base64的图片动态合并技术：</p>
<ul>
<li>&gt; 适用于页面中有很多小图（每张10k以下吧）、且无法离线合并的情况；</li>
<li>&gt; 适用的浏览器是IE8及以上、webkit等；</li>
<li>&gt; 其实Google很早就开始使用这种技术了，不过他们做得更绝一些：将图片转成base64后和html打包到了一起，随异步请求一并返回了，感兴趣的可以翻墙研究一下；</li>
<li>&gt; 服务端处理也很关键，拆分请求后去取图片，超时要做好控制，总体不能超过100ms，否则也是没收益的</li>
<li>&gt; CDN的缓存命中率也会有较大影响</li>
<li>&gt; 当图片过多导致单个请求耗时较长时，可以适当进行请求拆分</li>
<li>&gt; 总之做好各方面监控吧，看看瓶颈在哪里。</li>
</ul>
<p>如有问题，请联系 jesse2young@qq.com</p>
				</div>

				<p class="postmetadata">Tags: <a href="http://cubefe.com/tag/base64/" rel="tag">Base64</a>, <a href="http://cubefe.com/tag/%e5%9b%be%e7%89%87%e4%bc%98%e5%8c%96/" rel="tag">图片优化</a><br /> Posted in <a href="http://cubefe.com/category/wpo/" title="查看性能优化中的全部文章" rel="category tag">性能优化</a> |   <span>评论关闭</span></p>

			</div>
</div>
	<div id="postfooter"></div>
				<div id="test">
<div id="postheader"></div>
				<div class="post">
				<h3 id="post-241"><a href="http://cubefe.com/smarty_pre_compile/" rel="bookmark" title="Permanent Link to Smarty模板预编译">Smarty模板预编译</a></h3>
				<small>2013/08/07</small>

				<div class="entry">
					<h3><strong>背景</strong>：</h3>
<p>很多网站在使用Smarty模板做页面开发，上线时，大部分还是直接部署模板文件，没有提前对smarty模板进行编译。关于模板预编译，在网上资料也不多，以前我们也是直接上模板，到线上靠请求去触发编译，但发现这种方式对上线过程中的性能和流量损失非常严重，痛定思痛，研究和改造了smarty模板上线方式，找到了一个<strong>效果提升非常明显，且对开发和上线流程影响不大</strong>的方式，在这里跟各产品线分享一下，希望还没做改造的产品线尽快改造，提升线上产品的性能和稳定性。</p>
<h3><strong>什么是模板编译：</strong></h3>
<p>简单来讲：Smarty模板不是直接运行的，是会先经过一次编译，将模板转化成PHP脚本（缓存），放在/template_c目录下去执行。</p>
<h4>编译是怎么触发的<a name="编译是怎么触发的"></a></h4>
<p>编译的触发有两种方式：</p>
<p><strong>1. 运行时编译</strong>。首次HTTP请求。请求到模板时，Smarty检测到模板文件的时间戳发生了变化，对应的PHP缓存文件已经过期，就会触发编译；</p>
<p><strong>2. 预编译</strong>。通过运行php脚本编译命令启动Smarty模半编译。如：$smarty-&gt;utility-&gt;compileAllTemplates。 触发预编译的代码：</p>
<pre class="brush: php; title: ; notranslate" title="">&lt;/pre&gt;
require_once('/Smarty目录/smarty/Smarty.class.php');

Bd_Init::init();
$arrConf = Bd_Conf::getConf('/smarty/smarty配置文件');

$arrConf = array (
 'template_dir' =&gt; '/home/user/template/',
 'compile_dir' =&gt; '/home/编译目录/smartycompile/template/templates_c/',
 'compile_check' =&gt; '0',
 'config_dir' =&gt; '/home/user/template/config/',
 'config_load' =&gt; '',
 'plugins_dir' =&gt; '/home/user/template/plugin/',
 'left_delimiter' =&gt; '&lt;&amp;',
 'right_delimiter' =&gt; '&amp;&gt;',
);

$smarty = new Smarty;
$smarty-&gt;template_dir = $arrConf['template_dir'];
$smarty-&gt;compile_dir = $arrConf['compile_dir'];
$smarty-&gt;config_dir = $arrConf['config_dir'];
$smarty-&gt;cache_dir = $arrConf['cache_dir'];
$smarty-&gt;plugins_dir = array('plugins',$arrConf['plugins_dir']);
$smarty-&gt;left_delimiter = $arrConf['left_delimiter'];
$smarty-&gt;right_delimiter = $arrConf['right_delimiter'];

$util = new Smarty_Internal_Utility($smarty);
$suffix = $argv[1];
if ($suffix === null)
 $suffix = '.html';
$val = $util-&gt;compileAllTemplates($suffix, true);
&lt;pre&gt;</pre>
<h3><strong>上线方式:<a name="上线方式"></a></strong></h3>
<p>相对应Smarty模板的两种编译方式，我们的前端上线有两种方式：</p>
<p><strong>1. 运行时编译</strong>： 只上线模板文件，当有用户第一次请求时触发编译，生成php缓存文件。</p>
<p><strong>2. 预编译上线</strong>： 提前编译模板，直接上线编译后的php缓存文件。</p>
<h3><strong>运行时编译的问题：</strong></h3>
<p>运行时编译的问题是：编译期间，该模板功能无法使用，编译的耗时全部由用户来承担了。以前在使用运行时编译的时候发现，模板编译时长可以达到十几至几十秒。那么这期间落到这台机器上的请求，全部会被hang住，用户感觉到的响应很慢。</p>
<p>下图是上线时的模板响应耗时变化</p>
<p><img class="alignnone size-full wp-image-242" alt="" src="http://cubefe.com/wp-content/uploads/2013/08/image2013-1-3111-32-12.png" width="635" height="274" /></p>
<h3><strong>预编译上线：<a name="预编译上线"></a></strong></h3>
<p>预编译上线可以彻底解决运行时编译会hang住用户请求的问题。但同时也带来了新的挑战：在开发、测试和上线过程中，哪个阶段来做预编译比较合适？而预编译的结果又如何提交到产品库中或者 如何最终部署到线上机器？</p>
<p>几种方案对比：</p>
<p>1. 提测前编译，编译结果提交至产品库，随代码一起提测，发布上线。</p>
<p>缺点：研发提测前需要多一步操作：编译并提交产品库；另外，因为是单模块编译，不适合svn模块间有依赖的情况</p>
<p>2. 上线前编译，编译结果存放在某台机器上，上线时通过scp拷贝到其他线上机器。</p>
<p>缺点：文件拷贝很慢，没有历史版本记录，回滚不方便</p>
<p>3.  代码上线部署还是直接把tpl部署到线上机器（关闭compile_check），然后自动在机器上运行一个php脚本编译完成之后复制到template_c目录。</p>
<p>优点：全过程自动化，无手工操作。</p>
<p>缺点：每台机器都需要编译，有耗时，需验证每台机器编译结果是否一致。</p>
<p>4.  上线前，将模板部署到线上预览机，然后运行编译脚本，将编译结果提交到一个专门用来上线模板的产品库中（如fe/tpl-release），通过此产品库版本来上线</p>
<p>目前方案4是实际运行效果最好的。</p>
<h3><strong>效果回归：</strong></h3>
<p>改为smarty模板预编译上线的方式后，上线过程中模板耗时几乎没有变化：</p>
<p><img class="alignnone size-medium wp-image-245" alt="" src="http://cubefe.com/wp-content/uploads/2013/08/image2013-1-3111-32-121-800x244.png" width="800" height="244" /></p>
				</div>

				<p class="postmetadata">Tags: <a href="http://cubefe.com/tag/smarty/" rel="tag">smarty</a>, <a href="http://cubefe.com/tag/%e6%a8%a1%e6%9d%bf%e7%bc%96%e8%af%91/" rel="tag">模板编译</a><br /> Posted in <a href="http://cubefe.com/category/develop/" title="查看前端开发中的全部文章" rel="category tag">前端开发</a>, <a href="http://cubefe.com/category/wpo/" title="查看性能优化中的全部文章" rel="category tag">性能优化</a> |   <span>评论关闭</span></p>

			</div>
</div>
	<div id="postfooter"></div>
				<div id="test">
<div id="postheader"></div>
				<div class="post">
				<h3 id="post-94"><a href="http://cubefe.com/web-performence-monitoring/" rel="bookmark" title="Permanent Link to 基于phantomjs的前端性能监控">基于phantomjs的前端性能监控</a></h3>
				<small>2012/09/02</small>

				<div class="entry">
					<h2>前言</h2>
<p><strong>        </strong>性能优化的检测工具有很多，如yslow，pagespeed等。你可以通过这些工具来发现网站中可以优化的点，做有针对性的改进。但是，当你已经把网站优化到一个不错的程度时，如果这个网站还在不断地做快速的迭代升级，那么如何保证它的性能一直处于一个稳定的水平，就是一个必须要面对的问题了。</p>
<h2>性能监控</h2>
<p><strong>        </strong>“性能监控”说简单点就是将性能优化的检测工作放在命令行中去执行，制作成定时脚本，每天跑一下，将检测结果以邮件或报表的形式发送出来。去年velocity大会上，Yahoo团队为大家发布了yslow的命令行版本，大体就是用来做这样一件事情的。但更实际一些的问题是：如果这次的页面升级只是把原来已有的一个js增大了一些呢，或者如果不小心在页面里多引用了一个js呢？可能这种变化用yslow是检测不出来的，他会邮件你一个跟前一天一模一样的报表，但显然这次的升级对你的网页性能产生了影响。<br />
<strong>        </strong>为了能监测到这些很细节的变动，我们需要获得更详细的页面信息：如都发了哪些请求，加载了哪些JS、CSS，每个文件的大小是多少，页面整体大小、Dom元素数、CPU占用情况等等。这些信息的绝大部分，我们可以从HAR文件中获得。</p>
<h2>HAR(Http Archive)</h2>
<p><strong>        </strong><a title="HAR" href="http://www.softwareishard.com/blog/har-12-spec/" target="_blank">HAR</a>是一次页面打开相关的所有http请求信息的集合，可以从chrome控制台的页面瀑布流中右键另存为得到（如下图），也可以导入到<a title="HttpWatch" href="http://www.httpwatch.com/" target="_blank">HttpWatch</a>等工具中来查看。</p>
<p><a href="http://cubefe.com/web-performence-monitoring/2012-09-03_000038/" rel="attachment wp-att-112"><img class="alignnone size-full wp-image-112" title="2012-09-03_000038" src="http://cubefe.com/wp-content/uploads/2012/09/2012-09-03_000038.png" alt="" width="481" height="295" /></a></p>
<p>这里不做详细介绍了。那么如何获得一个页面的HAR文件？<a title="PhantomJS" href="http://phantomjs.org/index.html" target="_blank">PhantomJS</a>给我们提供了很方便的方式。</p>
<h2>PhantomJS</h2>
<p><strong>        </strong><a title="PhantomJS" href="http://phantomjs.org/index.html" target="_blank">PhantomJS</a>本质上是一个基于webkit内核的无界面浏览器，拥有完善的Javascript解析、页面渲染功能，你可以通过javascript编程，来模拟浏览器在加载网页时所做的任何事。<br />
<strong>        </strong>PhantomJS提供了一个netsniff.js的示例代码。通过以下命令可以生成一个页面的<strong>HAR</strong>文件:</p>
<pre class="brush: plain; title: ; wrap-lines: true; notranslate" title="">
phantomjs netsniff.js http://www.baidu.com &gt; har/$(date +%Y-%m-%d).har
</pre>
<p><strong>        </strong>HAR文件本身就是一个json字符串，通过任何的编程语言都可以进行解析。如PHP:</p>
<pre class="brush: php; title: ; notranslate" title="">
$_har_file = &quot;har/&quot;.date(&quot;Y-m-d&quot;).&quot;.har&quot;;
if(!file_exists($_har_file))
return;
$harContent = file_get_contents($_har_file);
$har = json_decode($harContent);
//加载时间
$loadTime = $har-&gt;log-&gt;pages[0]-&gt;pageTimings-&gt;onLoad;
//获取页面大小
$pageSize = $har-&gt;log-&gt;entries[0]-&gt;response-&gt;content-&gt;size;
//获取dom元素数
$domSize = $har-&gt;log-&gt;pages[0]-&gt;_domSize;
//获取外链文件
foreach($har-&gt;log-&gt;entries as $entry) {
   $url = $entry-&gt;request-&gt;url; //文件链接
   $entry-&gt;response-&gt;bodySize; //文件大小
}
</pre>
<p><strong>        </strong>那么接下来需要做的就是提取你所需要的信息，与历史数据进行比较即可。目前phantomjs暂不支持对cpu的检测。</p>
<h2>模拟登陆</h2>
<p><strong>       </strong>有些页面需要登陆之后才能访问，PhantomJS提供的netsniff.js是不支持登陆访问的，那么就需要对netsniff.js进行一些改造：</p>
<pre class="brush: jscript; title: ; notranslate" title="">
    var cookie_file = &quot;&quot;;
    system.args.forEach(function (arg, i) {
        if(arg.indexOf(&quot;--cookies-file&quot;) === 0){
            cookie_file = arg.slice(15, arg.length);
        }else {
            page.address = arg;
        }
    });

    if(cookie_file){
        var fs = require(&quot;fs&quot;);
        var f = fs.open(cookie_file, &quot;r&quot;);
        var cookie_content = f.read(f);
        cookie_content = cookie_content.replace(/\n/g, &quot;; &quot;);
        page.customHeaders = {Cookie:cookie_content};
    }
</pre>
<p><strong>       </strong>需要预先将cookie信息存入文件，如cookie.text，在调用的时候，增加以下参数：</p>
<pre class="brush: plain; title: ; wrap-lines: true; notranslate" title="">
phantomjs netsniff.js  --cookies-file=cookie.text http://www.baidu.com &gt; har/$(date +%Y-%m-%d).har
</pre>
<p><strong>       </strong>就可以实现登陆了。</p>
<h2>定时监测</h2>
<p><strong>       </strong>将phantomjs的命令写入shell文件，并通过crontab来每天定时执行，生成以当日日期为命名的.har文件，再通过执行php文件对当日的har文件进行解析，结果存入数据库或发送邮件即可，具体就不再详述了。</p>
<h2>构建报表</h2>
<p><strong>       </strong>通过对历史har文件中的静态文件进行匹配和提取，可以利用一些趋势图生成工具轻松的构建变化趋势图如下：</p>
<p><img class="alignnone size-full wp-image-98" src="http://cubefe.com/wp-content/uploads/2012/09/chart.png" alt="" width="600" height="300" /></p>
<h2>总结</h2>
<p><strong>        </strong>通过对phantomjs中netsniff.js的改造，我们可以实现以登录态抓取页面渲染的har文件，并通过构建定时程序，及对历史har文件的分析，可以实现对<strong>页面大小</strong>、<strong>加载时间</strong>、<strong>页面元素数</strong>、<strong>页面外链数</strong>、<strong>各外链文件大小</strong>等信息进行检测，如果发现页面信息有明显异常，如静态文件增多或增大超过一个自定义的百分比，就可以发送报警邮件，以实现性能问题的尽快定位和及时修复。</p>
				</div>

				<p class="postmetadata">Tags: <a href="http://cubefe.com/tag/phantomjs/" rel="tag">PhantomJS</a>, <a href="http://cubefe.com/tag/%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96/" rel="tag">性能优化</a>, <a href="http://cubefe.com/tag/%e6%80%a7%e8%83%bd%e7%9b%91%e6%8e%a7/" rel="tag">性能监控</a><br /> Posted in <a href="http://cubefe.com/category/wpo/" title="查看性能优化中的全部文章" rel="category tag">性能优化</a> |   <a href="http://cubefe.com/web-performence-monitoring/#comments" title="《基于phantomjs的前端性能监控》上的评论">4 Comments &#187;</a></p>

			</div>
</div>
	<div id="postfooter"></div>
				<div id="test">
<div id="postheader"></div>
				<div class="post">
				<h3 id="post-13"><a href="http://cubefe.com/wpo-practice/" rel="bookmark" title="Permanent Link to 前端重构实践（一）：性能优化">前端重构实践（一）：性能优化</a></h3>
				<small>2012/08/04</small>

				<div class="entry">
					<p><strong>前言</strong><br />
从去年Q4开始，百度新首页用了半年的时间完成了性能优化和模块化改造。在这里总结出一些经验和得失来帮助大家思考。共两篇文章，第一篇讨论性能优化，第二篇讨论模块化框架。而之所以把这两个话题放到一起，是因为这两项工作都涉及到对新首页前端代码进行不同程度的重构，而且模块化改造其实是我们在对性能优化做到一定程度之后发现必须要做的一件事情。本篇是性能优化的部分：</p>
<p><strong>场景分析：</strong><br />
百度首页一直以来以稳定和快速著称，很多网友都有习惯用百度首页来检查网络和网速是否正常。新版百度首页同样需要继承和发扬快速稳定的特点，但不同的是，新首页内部却又有着非常复杂的功能与交互。新首页第一版上线时，页面引用的js文件有3个，一共40-50k（压缩&amp;Gzip之后）。页面onload时间在1.3秒。<br />
1.3秒的load时间，相比较绝大多数网站来说都是一个不错的数值，但对于百度首页这样的产品定位还远远不够，老板也对此非常看重。性能优化成了新首页当时工作目标的重中之重。<br />
老板重视页面速度，对于Web前端开发人员来说其实是件幸事，这表明你将有更丰富的时间和资源去实践Web性能优化这一课题，不用被翻来覆去的产品升级需求所打扰。那么对于新首页，我们做了哪些实践：</p>
<p><strong>常规优化手段包括：</strong><br />
CSS置顶，JS置底。<br />
静态资源外联、合并、压缩。<br />
图片优化。（Png使用pngcrush；Gif使用gifsicle；Jpeg使用jpegtran）<br />
图片延迟加载。（主要针对首屏外的图片。）<br />
使用CSS Sprite，首屏图片全部合到一张图上。<br />
静态文件上CDN。（静态文件的下载能提速20%左右。）<br />
静态文件设置强缓存。（命中强缓存82.4%；命中若缓存3.4%；未命中缓存14.2%。）<br />
HTML压缩。（Gzip后减少%5。）</p>
<p><strong>增强型手段：</strong><br />
基础库定制。（用代码分析代码，自动打包被使用到的方法作为基础库，使基础库从原来的压缩后25K减小为9.8K,减小了61%）<br />
页面数据存储优化。（从原来的直接写json形式的script，变为将json隐藏在textarea中，初始化或用到的时候才去提取并进行解析。）<br />
首屏CSS检测。（对首屏用到的CSS进行检测，将不属于首屏的CSS代码单独打包并移到首屏之外进行延迟加载）<br />
js按需加载。（在后面做重点介绍）</p>
<p><strong>监控&amp; 测量</strong><br />
性能优化最重要的工作不是优化而是监控。这个道理很简单：没有监控体系就没办法衡量性能优化的效果，那么你所做的任何工作都是盲目的。<br />
我们对性能的监控是从多个维度展开的，包括平均时间、时段分布、浏览器分布、省份、运营商等。便于发现和定位任何一个细节的问题。<br />
而在平均时间这一维度，我们又分为四个级别：<br />
Head时间– head标签加载完成的时间<br />
TTi时间– 页面可交互时间（即首屏第一次渲染出来的时间）<br />
Dom时间– Dom Ready的时间<br />
Load 时间– 页面完全加载完成的时间</p>
<p>这样划分的好处是，页面加载每个环节的耗时一目了然：</p>
<p>Head ：CSS加载时间<br />
TTI ：整体HTML加载和渲染时间<br />
DOM 减TTI ： js文件网络传输时间和在浏览器进行解析的时间<br />
Load 减Dom : js初始化+ 图片加载的时间</p>
<p>而且，我们通过移动tti时间点的位置，发现了一个有趣的现象，如下图</p>
<p><a href="http://cubefe.com/wpo-practice/wpo-2/" rel="attachment wp-att-18"><img class="alignnone size-full wp-image-18" src="http://cubefe.com/wp-content/uploads/2012/08/wpo1.gif" alt="" width="568" height="451" /></a></p>
<p>可以看出，页面加载的性能瓶颈就在script的下载和解析时间。</p>
<p>为了进一步定位性能瓶颈，我们在页面内对用户网速进行了测试，结果很震惊：有2%的用户网速小于2k/s，5%的用户网速小于10k/s。（国内的网络状况真是惨不忍睹啊）<br />
那么，优化方案就很明显了：最大限度地减小js文件大小，以减小网络传输时间，提升页面性能。<br />
通过后来的优化工作我们发现：js代码压缩、Gzip后每减小1k，页面加载时间就能减小10ms左右。</p>
<p><strong>按需加载：</strong><br />
这是除了js压缩外，你能想到的最有效减小js文件大小的办法了。<br />
按需加载，顾名思义，就是在页面首次加载的时候只提供最需要的js给用户，而剩余的js等用户使用到了相关的功能再去加载。<br />
按需加载适合哪种类型的网站：如果80%的用户来到你的页面只使用20%的功能，那么就有必要把这20%的js作为首屏加载，而剩余的js做按需加载。<br />
从这个角度来讲，几乎所有网站都可以做按需加载，因为总有一些功能是用户很少会用到的。</p>
<p>那么，如何做按需加载：<br />
按需加载需要有一套js模块加载的框架。这个框架的作用是：保障在所需的js加载完成后才去执行回调方法。<br />
按需加载还需要有一套触发条件。在我们的页面中，对鼠标移动和鼠标点击都进行了监听，以保障在用户想使用某个功能之前或进行了相应操作时，触发js加载。</p>
<p>除此之外，我们还对js基础库进行了进一步拆分，分为首屏用到的基础方法，和延迟加载的js所需的基础方法。以最大限度地保证首屏js量的最小化。<br />
通过按需加载的拆分，我们将首屏的js代码从原来的gzip之后40-50k减小到了只有24k。<br />
同时，我们对CSS的加载也进行拆分，首屏不需要的CSS代码也随JS进行延迟加载。</p>
<p><strong>效果 &amp; 总结</strong><br />
性能优化是一个非常繁琐的工作，页面性能受很多因素的制约，不过相信一点：方法总比问题多。我们通过优化，最终将页面加载时间降到了650ms，仅为优化前的一半。所有优化工作中，效果最明显的就是js按需加载了。<br />
不过按需加载也为我们的代码结构带来了很大的冲击，极大地改变了我们写代码的方式，也制造了很多问题，我会在下一篇《前端重构——模块化框架实践》中进行详细介绍。</p>
				</div>

				<p class="postmetadata">Tags: <a href="http://cubefe.com/tag/%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96/" rel="tag">性能优化</a>, <a href="http://cubefe.com/tag/%e9%87%8d%e6%9e%84/" rel="tag">重构</a><br /> Posted in <a href="http://cubefe.com/category/wpo/" title="查看性能优化中的全部文章" rel="category tag">性能优化</a> |   <a href="http://cubefe.com/wpo-practice/#comments" title="《前端重构实践（一）：性能优化》上的评论">7 Comments &#187;</a></p>

			</div>
</div>
	<div id="postfooter"></div>
		
		<div class="navigation">
			<div class="alignleft"></div>
			<div class="alignright"></div>
		</div>
	</div>





	</div>

<div id="sidebar" role="complementary">
	<div id="sidebarhead"></div>
		<div id="sidebarinner">
		
			<ul>
		
				<li id="categories-2" class="widget widget_categories"><h2 class="widgettitle">分类目录</h2>		<ul>
	<li class="cat-item cat-item-7"><a href="http://cubefe.com/category/css/" title="查看CSS样式下的所有文章">CSS样式</a>
</li>
	<li class="cat-item cat-item-6"><a href="http://cubefe.com/category/develop/" title="查看前端开发下的所有文章">前端开发</a>
</li>
	<li class="cat-item cat-item-34"><a href="http://cubefe.com/category/%e5%90%8e%e7%ab%af%e5%bc%80%e5%8f%91/" title="查看后端开发下的所有文章">后端开发</a>
</li>
	<li class="cat-item cat-item-9"><a href="http://cubefe.com/category/trick/" title="查看奇淫技巧下的所有文章">奇淫技巧</a>
</li>
	<li class="cat-item cat-item-5 current-cat"><a href="http://cubefe.com/category/wpo/" title="查看性能优化下的所有文章">性能优化</a>
</li>
	<li class="cat-item cat-item-1"><a href="http://cubefe.com/category/uncategorized/" title="查看未分类下的所有文章">未分类</a>
</li>
	<li class="cat-item cat-item-12"><a href="http://cubefe.com/category/%e6%b5%8f%e8%a7%88%e5%99%a8%e6%8f%92%e4%bb%b6/" title="查看浏览器插件下的所有文章">浏览器插件</a>
</li>
		</ul>
</li><li id="tag_cloud-2" class="widget widget_tag_cloud"><h2 class="widgettitle">标签</h2><div class="tagcloud"><a href='http://cubefe.com/tag/base64/' class='tag-link-32' title='1个话题' style='font-size: 8pt;'>Base64</a>
<a href='http://cubefe.com/tag/css-2/' class='tag-link-21' title='1个话题' style='font-size: 8pt;'>css</a>
<a href='http://cubefe.com/tag/css%e4%bc%aa%e7%b1%bb/' class='tag-link-18' title='1个话题' style='font-size: 8pt;'>CSS伪类</a>
<a href='http://cubefe.com/tag/http/' class='tag-link-22' title='2个话题' style='font-size: 22pt;'>http</a>
<a href='http://cubefe.com/tag/https/' class='tag-link-31' title='1个话题' style='font-size: 8pt;'>https</a>
<a href='http://cubefe.com/tag/javascript/' class='tag-link-20' title='1个话题' style='font-size: 8pt;'>javascript</a>
<a href='http://cubefe.com/tag/nginx/' class='tag-link-30' title='2个话题' style='font-size: 22pt;'>nginx</a>
<a href='http://cubefe.com/tag/nodejs/' class='tag-link-35' title='1个话题' style='font-size: 8pt;'>nodejs</a>
<a href='http://cubefe.com/tag/phantomjs/' class='tag-link-16' title='1个话题' style='font-size: 8pt;'>PhantomJS</a>
<a href='http://cubefe.com/tag/smarty/' class='tag-link-25' title='1个话题' style='font-size: 8pt;'>smarty</a>
<a href='http://cubefe.com/tag/spdy/' class='tag-link-29' title='1个话题' style='font-size: 8pt;'>spdy</a>
<a href='http://cubefe.com/tag/tcp/' class='tag-link-23' title='1个话题' style='font-size: 8pt;'>tcp</a>
<a href='http://cubefe.com/tag/%e5%86%85%e5%ad%98%e6%b3%84%e9%9c%b2/' class='tag-link-11' title='1个话题' style='font-size: 8pt;'>内存泄露</a>
<a href='http://cubefe.com/tag/%e5%9b%be%e7%89%87%e4%bc%98%e5%8c%96/' class='tag-link-33' title='1个话题' style='font-size: 8pt;'>图片优化</a>
<a href='http://cubefe.com/tag/%e6%80%a7%e8%83%bd/' class='tag-link-28' title='1个话题' style='font-size: 8pt;'>性能</a>
<a href='http://cubefe.com/tag/%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96/' class='tag-link-4' title='2个话题' style='font-size: 22pt;'>性能优化</a>
<a href='http://cubefe.com/tag/%e6%80%a7%e8%83%bd%e7%9b%91%e6%8e%a7/' class='tag-link-15' title='1个话题' style='font-size: 8pt;'>性能监控</a>
<a href='http://cubefe.com/tag/%e6%a8%a1%e5%9d%97%e5%8c%96/' class='tag-link-10' title='1个话题' style='font-size: 8pt;'>模块化</a>
<a href='http://cubefe.com/tag/%e6%a8%a1%e6%9d%bf%e7%bc%96%e8%af%91/' class='tag-link-26' title='1个话题' style='font-size: 8pt;'>模板编译</a>
<a href='http://cubefe.com/tag/%e6%b5%8f%e8%a7%88%e5%99%a8%e7%89%b9%e6%80%a7/' class='tag-link-19' title='1个话题' style='font-size: 8pt;'>浏览器特性</a>
<a href='http://cubefe.com/tag/%e7%a7%bb%e5%8a%a8%e7%ab%af%e5%bc%80%e5%8f%91/' class='tag-link-27' title='1个话题' style='font-size: 8pt;'>移动端开发</a>
<a href='http://cubefe.com/tag/%e7%bc%93%e5%ad%98/' class='tag-link-24' title='1个话题' style='font-size: 8pt;'>缓存</a>
<a href='http://cubefe.com/tag/%e9%87%8d%e6%9e%84/' class='tag-link-3' title='2个话题' style='font-size: 22pt;'>重构</a></div>
</li>		<li id="recent-posts-2" class="widget widget_recent_entries">		<h2 class="widgettitle">近期文章</h2>		<ul>
					<li>
				<a href="http://cubefe.com/nginx_proxy_pass_sample/">Nginx反向代理设置</a>
						</li>
					<li>
				<a href="http://cubefe.com/img_base64/">一种基于Base64的图片动态合并下载技术</a>
						</li>
					<li>
				<a href="http://cubefe.com/smartycompletebug/">Smarty缓存编译出错问题</a>
						</li>
					<li>
				<a href="http://cubefe.com/spdy_first_step/">SPDY协议初步调研</a>
						</li>
					<li>
				<a href="http://cubefe.com/ipad_web_gpu_accelerate_animation/">iPad网页开发利用GPU加速JS动画</a>
						</li>
				</ul>
		</li><li id="recent-comments-2" class="widget widget_recent_comments"><h2 class="widgettitle">近期评论</h2><ul id="recentcomments"><li class="recentcomments"><a href='http://Jaimebait59.Webnode.com/news/first-blog/' rel='external nofollow' class='url'>increase your breast Size</a>发表在《<a href="http://cubefe.com/word-wrap-tips/#comment-110774">如何不让标点出现在行首 | CSS技巧</a>》</li><li class="recentcomments"><a href='http://watchtvonline-for-free.blogspot.com/' rel='external nofollow' class='url'>watch tv online</a>发表在《<a href="http://cubefe.com/word-wrap-tips/#comment-109909">如何不让标点出现在行首 | CSS技巧</a>》</li><li class="recentcomments"><a href='http://www.streetfire.net/profile/enemycellar00.htm' rel='external nofollow' class='url'>My Honest Review on John Collins Penis Enlargement Bible</a>发表在《<a href="http://cubefe.com/word-wrap-tips/#comment-109783">如何不让标点出现在行首 | CSS技巧</a>》</li><li class="recentcomments"><a href='http://www.youtube.com/watch?v=zutXI4W-OZc' rel='external nofollow' class='url'>android ice cream sandwich 4.0.4</a>发表在《<a href="http://cubefe.com/word-wrap-tips/#comment-109533">如何不让标点出现在行首 | CSS技巧</a>》</li><li class="recentcomments"><a href='http://youtu.be/VcdwKBKQYLU' rel='external nofollow' class='url'>Loto</a>发表在《<a href="http://cubefe.com/word-wrap-tips/#comment-109474">如何不让标点出现在行首 | CSS技巧</a>》</li></ul></li><li id="meta-2" class="widget widget_meta"><h2 class="widgettitle">功能</h2>			<ul>
						<li><a href="http://cubefe.com/wp-login.php">登录</a></li>
			<li><a href="http://cubefe.com/feed/" title="使用RSS 2.0订阅本站点内容">文章<abbr title="Really Simple Syndication">RSS</abbr></a></li>
			<li><a href="http://cubefe.com/comments/feed/" title="使用RSS订阅本站点的所有文章的近期评论">评论<abbr title="Really Simple Syndication">RSS</abbr></a></li>
			<li><a href="http://cn.wordpress.org/" title="基于WordPress，一个优美、先进的个人信息发布平台。">WordPress.org</a></li>						</ul>
</li>			</ul>
			
		</div>
		<div id="sidebarfooter"></div>
</div>
<div id="footer" role="contentinfo">
	 
		  
</div>
</div>
		<script type='text/javascript' src='http://cubefe.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter2/scripts/shCore.js?ver=2.1.364'></script>
<script type='text/javascript' src='http://cubefe.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter2/scripts/shBrushPhp.js?ver=2.1.364'></script>
<script type='text/javascript' src='http://cubefe.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter2/scripts/shBrushPlain.js?ver=2.1.364'></script>
<script type='text/javascript' src='http://cubefe.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter2/scripts/shBrushJScript.js?ver=2.1.364'></script>
<script type='text/javascript'>
	(function(){
		var corecss = document.createElement('link');
		var themecss = document.createElement('link');
		var corecssurl = "http://cubefe.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter2/styles/shCore.css?ver=2.1.364";
		if ( corecss.setAttribute ) {
				corecss.setAttribute( "rel", "stylesheet" );
				corecss.setAttribute( "type", "text/css" );
				corecss.setAttribute( "href", corecssurl );
		} else {
				corecss.rel = "stylesheet";
				corecss.href = corecssurl;
		}
		document.getElementsByTagName("head")[0].insertBefore( corecss, document.getElementById("syntaxhighlighteranchor") );
		var themecssurl = "http://cubefe.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter2/styles/shThemeMidnight.css?ver=2.1.364";
		if ( themecss.setAttribute ) {
				themecss.setAttribute( "rel", "stylesheet" );
				themecss.setAttribute( "type", "text/css" );
				themecss.setAttribute( "href", themecssurl );
		} else {
				themecss.rel = "stylesheet";
				themecss.href = themecssurl;
		}
		//document.getElementById("syntaxhighlighteranchor").appendChild(themecss);
		document.getElementsByTagName("head")[0].insertBefore( themecss, document.getElementById("syntaxhighlighteranchor") );
	})();
	SyntaxHighlighter.config.clipboardSwf = 'http://cubefe.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter2/scripts/clipboard.swf';
	SyntaxHighlighter.config.strings.expandSource = 'show source';
	SyntaxHighlighter.config.strings.viewSource = '查看源代码';
	SyntaxHighlighter.config.strings.copyToClipboard = '复制到剪贴板';
	SyntaxHighlighter.config.strings.copyToClipboardConfirmation = '代码现在在你的剪贴板';
	SyntaxHighlighter.config.strings.print = '打印';
	SyntaxHighlighter.config.strings.help = '帮助';
	SyntaxHighlighter.config.strings.alert = 'SyntaxHighlighter\n\n';
	SyntaxHighlighter.config.strings.noBrush = '无法找到Brush：';
	SyntaxHighlighter.config.strings.brushNotHtmlScript = 'Brush不能设置 html-script选项';
	SyntaxHighlighter.defaults['pad-line-numbers'] = false;
	SyntaxHighlighter.all();
</script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.core.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.widget.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.mouse.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.draggable.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.droppable.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.sortable.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.resizable.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.button.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.position.min.js?ver=1.10.3'></script>
<script type='text/javascript' src='http://cubefe.com/wp-includes/js/jquery/ui/jquery.ui.dialog.min.js?ver=1.10.3'></script>
</body>
</html>